package io.shuttle.mbe.api

import io.shuttle.mbe.api.annotation.ChromeMinVersion
import io.shuttle.mbe.api.annotation.PromiseStyleMinVersion
import io.shuttle.mbe.api.types.Value1Function
import io.shuttle.mbe.api.types.Value2Function
import io.shuttle.mbe.api.types.VoidFunction
import io.shuttle.mbe.core.Promise
import kotlinx.serialization.SerialName

////////////////////
// Bookmarks
////////////////////
/**
 * Use the `Browser.bookmarks` API to create, organize, and otherwise manipulate bookmarks. Also see Override Pages, which you can use to create a custom Bookmark Manager page.
 *
 * Permissions: "bookmarks"
 */
interface Bookmark {

    @Deprecated("Bookmark write operations are no longer limited by Chrome. default 1000000")
    val maxSustainedWriteOperationsPerMinute: Int

    @Deprecated("Bookmark write operations are no longer limited by Chrome. default 1000000")
    var maxWriteOperationsPerHour : Int

    // Creates a bookmark or folder under the specified parentId. If url is NULL or missing, it will be a folder.
    @PromiseStyleMinVersion(90)
     fun create(
        bookmark: CreateDetails,
        // @param {callback.result}
        callback: Value1Function<BookmarkTreeNode>? = null
    ): Promise<BookmarkTreeNode>

    // Retrieves the specified BookmarkTreeNode(s).
    @PromiseStyleMinVersion(90)
     fun get(
        // A single string-valued id, or an array of string-valued ids
        idOrIdList: IdOrIdList,
        callback: Value1Function<List<BookmarkTreeNode>>? = null,
    ): Promise<List<BookmarkTreeNode>>

    // Retrieves the children of the specified BookmarkTreeNode id.
    @PromiseStyleMinVersion(90)
     fun getChildren(
        id: String,
        callback: Value1Function<List<BookmarkTreeNode>>? = null,
    ): Promise<List<BookmarkTreeNode>>

    // Retrieves the recently added bookmarks.
    @PromiseStyleMinVersion(90)
     fun getRecent(
        // The maximum number of items to return.
        numberOfItems: Number,
        callback: Value1Function<List<BookmarkTreeNode>>? = null,
    ): Promise<List<BookmarkTreeNode>>

    // Retrieves part of the Bookmarks hierarchy, starting at the specified node.
    @PromiseStyleMinVersion(90)
     fun getSubTree(
        // The ID of the root of the subtree to retrieve.
        id: String,
        callback: Value1Function<List<BookmarkTreeNode>>? = null,
    ): Promise<List<BookmarkTreeNode>>

    // Retrieves the entire Bookmarks hierarchy.
    @PromiseStyleMinVersion(90)
     fun getTree(
        callback: Value1Function<List<BookmarkTreeNode>>? = null,
    ): Promise<List<BookmarkTreeNode>>

    // Moves the specified BookmarkTreeNode to the provided location.
    @PromiseStyleMinVersion(90)
     fun move(
        id: String,
        destination: MoveDestination,
        callback: Value1Function<BookmarkTreeNode>? = null
    ): Promise<BookmarkTreeNode>

    // Removes a bookmark or an empty bookmark folder.
    @PromiseStyleMinVersion(90)
     fun remove(
        id: String,
        callback: VoidFunction? = null
    ): Promise<Void>

    // Recursively removes a bookmark folder.
    @PromiseStyleMinVersion(90)
     fun removeTree(
        id: String,
        callback: VoidFunction? = null
    ): Promise<Void>

    /**
     * Searches for BookmarkTreeNodes matching the given query. Queries specified with an object produce BookmarkTreeNodes matching all specified properties.
     * @param query Either a string of words and quoted phrases that are matched against bookmark URLs and titles, or an object. If an object, the properties `query`, `url`, and `title` may be specified and bookmarks matching all specified properties will be produced.
     */
    @PromiseStyleMinVersion(90)
     fun search(
        query: SearchQuery,
        callback: Value1Function<List<BookmarkTreeNode>>? = null
    ): Promise<List<BookmarkTreeNode>>

    // Updates the properties of a bookmark or folder. Specify only the properties that you want to change;
    // unspecified properties will be left unchanged. Note: Currently, only 'title' and 'url' are supported.
    @PromiseStyleMinVersion(90)
     fun update(
        id: String,
        changes: UpdateChanges,
        callback: Value1Function<BookmarkTreeNode>? = null
    ): Promise<BookmarkTreeNode>

    // Fired when a bookmark or folder changes. Note: Currently, only title and url changes trigger this.
     val onChanged: Events.Event<Value2Function<String, UpdateChanges>>

    // Fired when the children of a folder have changed their order due to the order being sorted in the UI.
    // This is not called as a result of a move().
     val onChildrenReordered: Events.Event<Value2Function<String, RecordInfo>>

    // Fired when a bookmark or folder is created.
     val onCreated: Events.Event<Value2Function<String, BookmarkTreeNode>>

    // Fired when a bookmark import session is begun. Expensive observers should ignore onCreated updates until onImportEnded is fired.
    // Observers should still handle other notifications immediately.
     val onImportBegan: Events.Event<VoidFunction>

    // Fired when a bookmark import session is ended.
     val onImportEnded: Events.Event<VoidFunction>

    // Fired when a bookmark or folder is moved to a different parent folder.
     val onMoved: Events.Event<Value2Function<String, MoveInfo>>

    // Fired when a bookmark or folder is removed.
    // When a folder is removed recursively, a single notification is fired for the folder, and none for its contents.
     val onRemoved: Events.Event<Value2Function<String, RemoveInfo>>

    // A node (either a bookmark or a folder) in the bookmark tree. Child nodes are ordered within their parent folder.
    data class BookmarkTreeNode(
        // An ordered Array of children of this node.
        var children: List<BookmarkTreeNode>? = null,
        // When this node was created, in milliseconds since the epoch (new Date(dateAdded)).
        var dateAdded: Number? = null,
        // When the contents of this folder last changed, in milliseconds since the epoch.
        var dateGroupModified: Number? = null,
        // When this node was last opened, in milliseconds since the epoch. Not set for folders.
        @ChromeMinVersion(114)
        var dateLastUsed: Number? = null,
        // f present, this is a folder that is added by the browser and that cannot be modified by the user or the extension.
        // Child nodes may be modified, if this node does not have the unmodifiable property set.
        // Omitted if the node can be modified by the user and the extension (default).
        //
        //There may be zero, one or multiple nodes of each folder type.
        // A folder may be added or removed by the browser, but not via the extensions API.
        @ChromeMinVersion(134)
        var folderType: FolderType? = null,
        // The unique identifier for the node.
        // IDs are unique within the current profile, and they remain valid even after the browser is restarted.
        var id: String,
        // The 0-based position of this node within its parent folder.
        var index: Number? = null,
        // The id of the parent folder. Omitted for the root node.
        var parentId: String? = null,
        // Whether this node is synced with the user's remote account storage by the browser.
        // This can be used to distinguish between account and local-only versions of the same FolderType.
        // The value of this property may change for an existing node, for example as a result of user action.
        //
        //Note: this reflects whether the node is saved to the browser's built-in account provider.
        // It is possible that a node could be synced via a third-party, even if this value is false.
        //
        //For managed nodes (nodes where unmodifiable is set to true), this property will always be false.
        @ChromeMinVersion(134)
        var syncing: Boolean = false,
        // The text displayed for the node.
        var title: String,
        // Indicates the reason why this node is unmodifiable.
        // The managed value indicates that this node was configured by the system administrator or by the custodian of a supervised user.
        // Omitted if the node can be modified by the user and the extension (default).
        var unmodifiable: BookmarkTreeNodeUnmodifiable? = null,
        // The URL navigated to when a user clicks the bookmark. Omitted for folders.
        var url: String? = null,
    )

    @ChromeMinVersion(134)
    enum class FolderType {
        // The folder whose contents is displayed at the top of the browser window.
        @SerialName("bookmarks-bar")
        BookmarksBar,

        // Bookmarks which are displayed in the full Array of bookmarks on all platforms.
        other,

        // Bookmarks generally available on the user's mobile devices, but modifiable by extension or in the bookmarks manager.
        mobile,

        // A top-level folder that may be present if the system administrator or the custodian of a supervised user has configured bookmarks.
        managed
    }

    // Indicates the reason why this node is unmodifiable. The managed value indicates that this node was configured by the system administrator. Omitted if the node can be modified by the user and the extension (default).
    @ChromeMinVersion(44)
    enum class BookmarkTreeNodeUnmodifiable {
        managed
    }

    data class CreateDetails(
        var index: Number? = null,
        // Defaults to the Other Bookmarks folder.
        var parentId: String? = null,
        var title: String? = null,
        var url: String? = null,
    )

    data class MoveDestination(
        var index: Number? = null,
        var parentId: String? = null
    )

    data class MoveInfo(
        var index: Number,
        var oldIndex: Number,
        var oldParentId: String,
        var parentId: String
    )

    data class RemoveInfo(
        var index: Number,
        @ChromeMinVersion(48)
        var node: BookmarkTreeNode,
        var parentId: String
    )

    sealed class IdOrIdList {
        data class Id(val id: String) : IdOrIdList()
        data class IdList(val idList: List<String>) : IdOrIdList()
    }

    // Either a string of words and quoted phrases that are matched against bookmark URLs and titles, or an object.
    // If an object, the properties query, url, and title may be specified and bookmarks matching all specified properties will be produced.
    sealed class SearchQuery {
        data class Str(val keyword: String) : SearchQuery()
        data class Object(val queryObject: SearchQueryObject) : SearchQuery()
    }

    data class SearchQueryObject(
        // A string of words and quoted phrases that are matched against bookmark URLs and titles.
        val query: String? = null,
        // The title of the bookmark; matches verbatim.
        var title: String? = null,
        // The URL of the bookmark; matches verbatim. Note that folders have no URL.
        var url: String? = null,
    )

    data class UpdateChanges(
        var title: String? = null,
        var url: String? = null,
    )

    data class RecordInfo(val childIds: List<String>)
}